﻿using System;
using System.Collections.Generic;
using System.Linq;
using com.eforceglobal.crux.configuration;
using com.eforceglobal.crux.configuration.DTOs;
using com.eforceglobal.crux.notifications;
using com.eforceglobal.crux.web.wrokflows;
using com.eforceglobal.crux.web.wrokflows.DTOs;

namespace com.eforcegloabal.crux.web.wrokflows
{
    public class WorkflowEmailNotifications
    {
        readonly BusinessObjectsDataContext _bc = new BusinessObjectsDataContext(CruxConfigurationManager.GetCruxDBConnectionString());

        public IEnumerable<NotificationModeInfo> GetNotificationModes()
        {
            IEnumerable<NotificationModeInfo> notificationModes =
                from notificationMode in _bc.NotificationModes
                select NotificationClassConverter.CopyNotificationModeToNotificationModeInfo(notificationMode);
            return notificationModes;
        }
        public IEnumerable<NotificationStateInfo> GetNotificationStates()
        {
            IEnumerable<NotificationStateInfo> notificationStates =
                            from notificationState in _bc.NotificationStates
                            select NotificationClassConverter.CopyNotificationStateToNotificationStateInfo(notificationState);
            return notificationStates;
        }
        public IEnumerable<NotificationStateModesInfo> GetNotificationStateModeSetByUserId(string userName)
        {
            IEnumerable<NotificationStateModesInfo> notificationStateModeSets =
                from notificationStateModeSet in _bc.NotificationStateModes
                where notificationStateModeSet.UserName.Equals(userName)
                select NotificationClassConverter.CopyStateModeSetToStateModeSetInfo(notificationStateModeSet);
            return notificationStateModeSets;
        }

        public void SaveNotificationStateModes(List<NotificationStateModesInfo> lstNotificationStateModesInfo)
        {
            try
            {
                string userName = lstNotificationStateModesInfo.First().UserName;
                var stateModeSet = GetNotificationStateModeSetBusinessObjectByUserId(userName);
                _bc.NotificationStateModes.DeleteAllOnSubmit(stateModeSet);
                _bc.SubmitChanges();
                if (lstNotificationStateModesInfo.Count == 1)
                {
                    if (lstNotificationStateModesInfo.First().NotificationModeId == 0 || lstNotificationStateModesInfo.First().NotificationStateId == 0)
                    {
                        return;
                    }
                }
                InsertSelectedModeState(lstNotificationStateModesInfo);
                _bc.SubmitChanges();
            }
            catch (Exception ex)
            {
                throw new WorkflowNotificationException(ex.Message);
            }
        }

        public void SaveNotificationStateModesOnUserRoles(string userName, List<string> roles)
        {
            var lstWorkflowStates = GetNotificationStates();
            if (lstWorkflowStates == null)
                throw new WorkflowNotificationException("No Workflow States Found in NotificationState Table.");
            var workflowNames = (from ws in lstWorkflowStates
                                 select ws.WorkflowName).Distinct().ToList();
            var lstWorkflowStatesInfoForTheUser = new List<WorkflowStatesInfo>();
            foreach (var workflowName in workflowNames)
            {
                Workflow workflowInfo = ConfigParser.GetWorkflowConfiguration(workflowName);
                var workflowStatesInfo = GetWorkflowStatesForTheUserRoles(userName, roles, workflowInfo);
                lstWorkflowStatesInfoForTheUser.Add(workflowStatesInfo);
            }

            var notificationMode = GetNotificationModes().Where(md => md.NotificationInterval.Equals("Real Time")).FirstOrDefault();
            if (notificationMode == null)
                throw new WorkflowNotificationException("Real Time NotificationInterval Value Not Found in NotificationMode Table. One NotificationInterval Value Should be NULL For Real Time Notification.");
            long realTimeModeId = notificationMode.NotificationModeId;

            var lstNotificationStateModesInfo = new List<NotificationStateModesInfo>();
            foreach (var statesInfoForTheUser in lstWorkflowStatesInfoForTheUser)
            {
                List<long> notificationStateIds = (from st in lstWorkflowStates
                                                   where statesInfoForTheUser.WorkflowName.Equals(st.WorkflowName)
                                                   where statesInfoForTheUser.States.Contains(st.StateName)
                                                   select st.NotificationStateId).ToList();

                foreach (var notificationStateId in notificationStateIds)
                {
                    lstNotificationStateModesInfo.Add(new NotificationStateModesInfo
                                                          {
                                                              NotificationModeId = realTimeModeId,
                                                              NotificationStateId = notificationStateId,
                                                              UserName = userName,
                                                          });
                }
            }
            if (lstNotificationStateModesInfo.Count != 0)
                SaveNotificationStateModes(lstNotificationStateModesInfo);
        }
        public void DeleteNotificationStateModesByUserName(string userName)
        {
            var stateModeSet = _bc.NotificationStateModes.Where(n => n.UserName.Equals(userName));
            _bc.NotificationStateModes.DeleteAllOnSubmit(stateModeSet);
            _bc.SubmitChanges();
        }
        public void DeleteNotificationStateModeSet(List<NotificationStateModesInfo> lstNotificationStateModesInfo)
        {
            var lstNotificationStateModeSet = new List<NotificationStateMode>();
            foreach (var notificationStateModesInfo in lstNotificationStateModesInfo)
            {
                var stateModeSet = _bc.NotificationStateModes.Where(n => n.NotificationStateModeId == notificationStateModesInfo.NotificationStateModeId).FirstOrDefault();
                lstNotificationStateModeSet.Add(stateModeSet);
            }
            _bc.NotificationStateModes.DeleteAllOnSubmit(lstNotificationStateModeSet);
            _bc.SubmitChanges();
        }

        private IEnumerable<NotificationStateMode> GetNotificationStateModeSetBusinessObjectByUserId(string userName)
        {
            return from stateModeSet in _bc.NotificationStateModes
                   where stateModeSet.UserName.Equals(userName)
                   select stateModeSet;
        }
        private void InsertSelectedModeState(List<NotificationStateModesInfo> selectedStateModeSets)
        {
            var dbSelectedStateModeSet = new List<NotificationStateMode>();
            dbSelectedStateModeSet = NotificationClassConverter.CopyNotificationStateModeSetInfoListToNotificationStateModeSet(selectedStateModeSets, dbSelectedStateModeSet);
            _bc.NotificationStateModes.InsertAllOnSubmit(dbSelectedStateModeSet);
        }
        private static WorkflowStatesInfo GetWorkflowStatesForTheUserRoles(string userName, List<string> roles, Workflow workflowInfo)
        {
            List<string> states = new List<string>();
            foreach (Activity activity in workflowInfo.Activites)
            {
                var routingRule = ConfigParser.GetRoutingRuleForTheActivity(workflowInfo.WorkflowName, activity.ActivityName, activity.State);
                var ruleValue = new RoutingRuleManager().GetRoutingValue(routingRule, userName, roles);
                if (ruleValue == true)
                {
                    states.Add(activity.State);
                }
            }
            var workflowStatesInfo = new WorkflowStatesInfo
                                         {
                                             WorkflowName = workflowInfo.WorkflowName,
                                             States = states
                                         };
            return workflowStatesInfo;
        }

        private IEnumerable<NotificationStateMode> GetNotificationStateModesByState(string workflowname, string statename)
        {
            IEnumerable<NotificationStateMode> notificationStateModeSets =
                    from notificationStateModeSet in _bc.NotificationStateModes
                    where notificationStateModeSet.NotificationState.StateName == statename
                    where notificationStateModeSet.NotificationState.WorkflowName == workflowname
                    select notificationStateModeSet;
            return notificationStateModeSets;
        }

        public void AppendWorkflowNotifications(string workflowname, string statename, int workflowinstanceid)
        {
            List<NotificationStateMode> notificationstates = GetNotificationStateModesByState(workflowname, statename).ToList();
            List<NotificationInstance> notifications = new List<NotificationInstance>();
            foreach (var notificationstate in notificationstates)
            {
                NotificationInstance notification = new NotificationInstance();
                notification.UserName = notificationstate.UserName;
                notification.WorkflowInstanceId = workflowinstanceid;
                notification.WorkflowName = workflowname;
                notification.StateName = statename;
                //TODO: make dynamic
                WorkflowManager manager = new WorkflowManager();
                List<DbAttribute> attributes = manager.GetAttributes(workflowinstanceid);
                List<KeyValuePair<string,string>> values = new List<KeyValuePair<string,string>>();
                foreach(DbAttribute attribute in attributes)
                {
                    KeyValuePair<string, string> value = new KeyValuePair<string,string>(attribute.Name, attribute.Value);
                    values.Add(value);
                }
                string emailaction = ConfigParser.GetEmailActionForActivity(workflowname, statename);

                notification.NotificationSubject = MailMan.ReplaceTagsInSubject (values, emailaction);
                notification.NotificationBody = MailMan.ReplaceTagsInBody(values, emailaction);
                notification.NotificationSent = false;
                notification.GenerationTime = DateTime.Now;
                notifications.Add(notification);
            }
            _bc.NotificationInstances.InsertAllOnSubmit(notifications);
            _bc.SubmitChanges();
        }

    }
}
